using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace EventBehaviorTree
{
    [Serializable]
    public abstract class Container : EventNode
    {
        protected List<EventNode> _subNodes;
        protected int _stepCount = 0;
        protected AsyncWorker _asyncWorker;
        [NonSerialized] protected MonoBehaviour _coroutineStarter;
        protected Dictionary<NodeMsg, NodeMsg> _msgChart;
        public Container()
        {
            _isWorking = false;
            _subNodes = new List<EventNode>();
            _msgChart = new Dictionary<NodeMsg, NodeMsg>
            {
                { NodeMsg.Succeed, NodeMsg.Succeed },
                { NodeMsg.Fail, NodeMsg.Fail },
                { NodeMsg.REQ_Abort, NodeMsg.REQ_Abort }
            };
        }
        public Container(KeyValuePair<NodeMsg, NodeMsg>[] msgPairs, params NodeMsg[] silencedMsg) : this()
        {
            for (int i = 0; i < msgPairs.Length; i++)
            {
                if (_msgChart.ContainsKey(msgPairs[i].Key))
                {
                    _msgChart[msgPairs[i].Key] = msgPairs[i].Value;
                }
                else _msgChart.Add(msgPairs[i].Key, msgPairs[i].Value);
            }
            foreach (var msg in silencedMsg)
            {
                if (_msgChart.ContainsKey(msg)) _msgChart.Remove(msg);
            }
        }

        /// <summary>
        /// Add node to the list and set the key for subNode.
        /// </summary>
        /// <param name="subNodes"></param>
        public void AddSubNode(params EventNode[] subNodes)
        {
            foreach (var subNode in subNodes)
            {
                _subNodes.Add(subNode);
                subNode.SetKey(Key + "." + _stepCount);
                _stepCount++;
                subNode.SetReceiver(NodeEvent);
                subNode.SetCoroutineStarter(_coroutineStarter);
            }
        }

        public override void SetCoroutineStarter(MonoBehaviour coroutineStarter)
        {
            _asyncWorker = new AsyncWorker(coroutineStarter);
            _coroutineStarter = coroutineStarter;
            foreach (EventNode subNode in _subNodes) { subNode.SetCoroutineStarter(coroutineStarter); }
        }

        protected virtual IEnumerator Worker() { yield return null; }

        protected void StartWithEnumerator()
        {
            _isWorking = true;
            _stepCount = 0;
            _asyncWorker.ResetWorker(Worker());
            _asyncWorker.Start();
        }

        protected void StopWithEnumerator()
        {
            _asyncWorker.ResetWorker(Worker());
            StopAllSubNodes();
            _isWorking = false;
        }

        protected void StopAllSubNodes()
        {
            foreach (EventNode subNode in _subNodes) subNode.NodeEvent(NodeMsg.CMD_Stop);
        }

        protected void SendMessage(NodeMsg key)
        {
            if (_msgChart.ContainsKey(key)) SuperiorNodeEvent(_msgChart[key]);
        }
    }
}